/*
 *  ckr_spec_console_spec_runner_specs.cpp
 *  ckrSpec
 *
 *  Created by C. Keith Ray on 2006.11.13.
 *  Copyright 2006 __MyCompanyName__. All rights reserved.
 *
 */

#include <sstream>
#include <iostream>
#include "ckr_spec_cpp_specs.h"
#include "ckr_spec_cpp.h"
#include "ckr_spec_ConsoleSpecRunner.h"


using namespace std;
using namespace ckr;

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void spec_stdString_fillingCharsToWidth();

static void consoleSpecRunner_outputs_menu();
static void consoleSpecRunner_processes_command();

static void consoleSpecRunner_processes_run_all_command();
static void consoleSpecRunner_processes_ra_command();

static void consoleSpecRunner_processes_ra_command_with_failing();

static void consoleSpecRunner_processes_run_fast_command();
static void consoleSpecRunner_processes_rf_command();

static void consoleSpecRunner_processes_run_new_command();
static void consoleSpecRunner_processes_rn_command();

static void consoleSpecRunner_processes_list_all_command();
static void consoleSpecRunner_processes_list_failing_command();
static void consoleSpecRunner_processes_list_quick_command();
static void consoleSpecRunner_processes_list_new_command();
static void consoleSpecRunner_processes_list_selected_command();

static void consoleSpecRunner_processes_summary_command();
static void consoleSpecRunner_processes_quit_exit_command();

static void consoleSpecRunner_processes_selectName();
static void consoleSpecRunner_processes_selectNameDashName();
static void consoleSpecRunner_processes_selectNameCommaName();

static void consoleSpecRunner_processes_clear_command();
static void consoleSpecRunner_processes_cl_command();

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

void run_consoleSpecRunner_specs()
{
	spec_stdString_fillingCharsToWidth();

	consoleSpecRunner_outputs_menu();
	consoleSpecRunner_processes_command();

	consoleSpecRunner_processes_run_all_command();
	consoleSpecRunner_processes_ra_command();
	consoleSpecRunner_processes_ra_command_with_failing();

	consoleSpecRunner_processes_run_fast_command();
	consoleSpecRunner_processes_rf_command();

	consoleSpecRunner_processes_run_new_command();
	consoleSpecRunner_processes_rn_command();

	consoleSpecRunner_processes_list_all_command();
	consoleSpecRunner_processes_list_failing_command();
	
	consoleSpecRunner_processes_summary_command();
	consoleSpecRunner_processes_quit_exit_command();

	consoleSpecRunner_processes_selectName();
	consoleSpecRunner_processes_selectNameDashName();
	consoleSpecRunner_processes_selectNameCommaName();

	consoleSpecRunner_processes_clear_command();
	consoleSpecRunner_processes_cl_command();

	consoleSpecRunner_processes_list_quick_command();
	consoleSpecRunner_processes_list_new_command();
	consoleSpecRunner_processes_list_selected_command();
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void spec_stdString_fillingCharsToWidth()
{
	const std::string shortWord("short");
	const std::string shortPadded = padWithSpaces( shortWord, 10 );
	
	assert( shortPadded == "short     " );
	
	const std::string longWord("long word");
	const std::string longPadded = padWithSpaces( longWord, 9 );
	
	assert( longPadded == "long word" );
	
	const std::string longPaddedShort = padWithSpaces( longWord, 5 );
	
	assert( longPaddedShort == "long word" );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_outputs_menu()
{
	std::stringstream  outStream;
	
	ConsoleSpecRunner runner;
	runner.outputMenu( outStream );
	
	std::string actual = outStream.str();
	const std::string expected = ConsoleSpecRunner::kMenuString;

	assert( expected == actual );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_command()
{
	std::stringstream  inStream("any text\n"); // any unrecognized input 
	std::stringstream  outStream; // results in listing the commands.
	
	ConsoleSpecRunner runner;
	runner.processInput( outStream, inStream );

	std::string actual = outStream.str();
	const std::string expected = ConsoleSpecRunner::kMenuString;
		
	assert( expected == actual );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class PassingOneSecondSpec : public ckr::Context
{
public:
	std::stringstream* log;

	PassingOneSecondSpec() 
		: ckr::Context("PassingOneSecondSpec",__LINE__, __FILE__)
		, log( NULL )
	{ };

	virtual double duration() const
	{ return 1.0; };

	virtual void spec()
	{
		if ( log != NULL )
		{
			(*log) << "PassingOneSecondSpec; ";
		}
	}
};

class PassingHalfSecondSpec : public ckr::Context
{
public:
	std::stringstream* log;

	PassingHalfSecondSpec() 
		: ckr::Context("PassingHalfSecondSpec",__LINE__, __FILE__)
		, log( NULL )
	{ };

	virtual double duration() const
	{ return 0.5; };

	virtual void spec()
	{
		if ( log != NULL )
		{
			(*log) << "PassingHalfSecondSpec; ";
		}
	}
};

static void consoleSpecRunner_processes_run_all_command()
{
	std::stringstream  inStream( ConsoleSpecRunner::kRunCmd + " " + kAllCmd + "\n" ); 
	std::stringstream  outStream;
	
	ConsoleSpecRunner runner;
	PassingOneSecondSpec oneSecond;
	PassingHalfSecondSpec halfSecond;
	runner.add( & oneSecond );
	runner.add( & halfSecond );

	runner.processInput( outStream, inStream );

	std::string actual = outStream.str();
	const std::string expected = "..\n" // two tests run
								"SUCCESS; 2 ran; 0 failed; 1.5 seconds\n\n"; // success summary
		
	assert( expected == actual );
}

static void consoleSpecRunner_processes_ra_command()
{
	std::stringstream  inStream( ConsoleSpecRunner::kRunAllAbbrev + "\n" ); 
	std::stringstream  outStream;
	
	ConsoleSpecRunner runner;
	PassingOneSecondSpec oneSecond;
	PassingHalfSecondSpec halfSecond;
	runner.add( & oneSecond );
	runner.add( & halfSecond );

	runner.processInput( outStream, inStream );

	std::string actual = outStream.str();
	const std::string expected = "..\nSUCCESS; 2 ran; 0 failed; 1.5 seconds\n\n";
		
	assert( expected == actual );
}

static void consoleSpecRunner_processes_ra_command_with_failing()
{
	std::stringstream  inStream( ConsoleSpecRunner::kRunAllAbbrev + "\n" ); 
	std::stringstream  outStream;
	
	ConsoleSpecRunner runner;
	PassingOneSecondSpec oneSecond;
	FailingSpec failing;
	failing.setDuration( 0.5 );
	runner.add( & oneSecond );
	runner.add( & failing );

	runner.processInput( outStream, inStream );

	std::string actual = outStream.str();
	const std::string expected = ".F\nFAILED; 2 ran; 1 failed; 1.00001 seconds\n"
				"intentional failure FAILED in FailingSpec; line ";

		std::string::size_type foundPos = actual.find( expected, 0 );
		assert( foundPos != std::string::npos );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_run_fast_command()
{
	std::stringstream  inStream( ConsoleSpecRunner::kRunCmd + " " + kQuickOnlyCmd + "\n" ); 
	std::stringstream  outStream;
	
	ConsoleSpecRunner runner;
	PassingOneSecondSpec oneSecond;
	PassingHalfSecondSpec halfSecond;

	runner.add( & oneSecond );
	runner.add( & halfSecond );

	runner.processInput( outStream, inStream );

	std::string actual = outStream.str();
	const std::string expected = ".\nSUCCESS; 1 ran; 0 failed; 0.5 seconds\n\n";
		
	assert( expected == actual );
}

static void consoleSpecRunner_processes_rf_command()
{
	std::stringstream  inStream( ConsoleSpecRunner::kRunQuickOnlyAbbrev + "\n" ); 
	std::stringstream  outStream;
	
	ConsoleSpecRunner runner;
	PassingOneSecondSpec oneSecond;
	PassingHalfSecondSpec halfSecond;

	runner.add( & oneSecond );
	runner.add( & halfSecond );

	runner.processInput( outStream, inStream );

	std::string actual = outStream.str();
	const std::string expected = ".\nSUCCESS; 1 ran; 0 failed; 0.5 seconds\n\n";
		
	assert( expected == actual );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_run_new_command()
{
	std::stringstream  inStream( ConsoleSpecRunner::kRunCmd + " " + kNewFirstCmd + "\n" ); 
	std::stringstream  outStream;
	std::stringstream  testOrderStream;

	ConsoleSpecRunner runner;

	PassingHalfSecondSpec halfSecond;
	halfSecond.setHasBeenRun( true ); // this should run second
	halfSecond.log = & testOrderStream;

	PassingOneSecondSpec oneSecond;
	oneSecond.setHasBeenRun( false ); // this should run first
	oneSecond.log = & testOrderStream;

	runner.add( & oneSecond );
	runner.add( & halfSecond );

	runner.processInput( outStream, inStream );

	std::string actual = outStream.str();
	const std::string expected = "..\nSUCCESS; 2 ran; 0 failed; 1.5 seconds\n\n";
		
	assert( expected == actual );
	
	std::string actualOrder = testOrderStream.str();
	const std::string expectedOrder = "PassingHalfSecondSpec; PassingOneSecondSpec; ";
	
	assert( expectedOrder == actualOrder );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_rn_command()
{
	std::stringstream  inStream( ConsoleSpecRunner::kRunNewFirstAbbrev + "\n" ); 
	std::stringstream  outStream;
	std::stringstream  testOrderStream;

	ConsoleSpecRunner runner;

	PassingHalfSecondSpec halfSecond;
	halfSecond.setHasBeenRun( true ); // this should run second
	halfSecond.log = & testOrderStream;

	PassingOneSecondSpec oneSecond;
	oneSecond.setHasBeenRun( false ); // this should run first
	oneSecond.log = & testOrderStream;

	runner.add( & oneSecond );
	runner.add( & halfSecond );

	runner.processInput( outStream, inStream );

	std::string actual = outStream.str();
	const std::string expected = "..\nSUCCESS; 2 ran; 0 failed; 1.5 seconds\n\n";
		
	assert( expected == actual );
	
	std::string actualOrder = testOrderStream.str();
	const std::string expectedOrder = "PassingHalfSecondSpec; PassingOneSecondSpec; ";
	
	assert( expectedOrder == actualOrder );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void addSilverEtcToRunner( ConsoleSpecRunner& runner, 
					ContextList& listToDelete )
{
	Context* silver = new Context( "Silver", __LINE__, __FILE__ );
	silver->setHasBeenRun( true );
	silver->setHasFailed( true );
	silver->setDuration( 1.0 );
	double dur = silver->duration();

	Context* gold = new Context( "Gold", __LINE__, __FILE__ );
	gold->setHasBeenRun( true );
	gold->setHasFailed( false );
	gold->setDuration( 2.0 );
	dur = gold->duration();

	Context* copper = new Context( "copper", __LINE__, __FILE__ );
	copper->setHasBeenRun( false );
	copper->setHasFailed( false );
	copper->setDuration( 3.0 );
	dur = copper->duration();

	Context* iron = new Context( "iron", __LINE__, __FILE__ );
	iron->setHasBeenRun( false );
	iron->setHasFailed( true );
	iron->setDuration( 4.0 );
	dur = iron->duration();
	assert( fabs(4.0 - dur) < 0.0001 );

	runner.add( silver );
	runner.add( gold );
	runner.add( copper );
	runner.add( iron );

	listToDelete.push_back( silver );
	listToDelete.push_back( gold );
	listToDelete.push_back( copper );
	listToDelete.push_back( iron );
}

static void deleteListContexts( ContextList& listToDelete )
{
	for ( ContextList::iterator i = listToDelete.begin(); 
		i != listToDelete.end(); ++i )
	{
		Context* c = *i;
		delete c;
	}
	listToDelete.clear();
}

static void consoleSpecRunner_processes_list_all_command()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kListCmd + " " + kAllCmd + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );

		runner.processInput( outStream, inStream );
		{
			std::string actual = outStream.str();  // alphabetical (case insensitive) order
			std::string expected =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"copper  pass    no          3         \n"
							"Gold    pass    yes         2         \n"
							"iron    FAIL    no          4         \n"
							"Silver  FAIL    yes         1         \n\n\n";

			assert( expected == actual );
		}
		{
			std::stringstream  inStream2( ConsoleSpecRunner::kListAllAbbrev + "\n" ); 
			std::stringstream  outStream2;

			runner.processInput( outStream2, inStream2 );

			std::string actual2 = outStream2.str();  // alphabetical (case insensitive) order
			std::string expected2 =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"copper  pass    no          3         \n"
							"Gold    pass    yes         2         \n"
							"iron    FAIL    no          4         \n"
							"Silver  FAIL    yes         1         \n\n\n";

			assert( expected2 == actual2 );
		}
	}
	deleteListContexts( contexts );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_list_failing_command()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kListCmd + " " + kFailingCmd + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );

		runner.processInput( outStream, inStream );
		{
			std::string actual = outStream.str();  // alphabetical (case insensitive) order
			std::string expected =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"Silver  FAIL    yes         1         \n\n\n";

			assert( expected == actual );
		}
		{
			std::stringstream  inStream2( ConsoleSpecRunner::kListFailingAbbrev + "\n" ); 
			std::stringstream  outStream2;

			runner.processInput( outStream2, inStream2 );

			std::string actual2 = outStream2.str();  // alphabetical (case insensitive) order
			std::string expected2 =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"Silver  FAIL    yes         1         \n\n\n";

			assert( expected2 == actual2 );
		}
	}
	deleteListContexts( contexts );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_summary_command()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kSummaryCmd + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );

		runner.processInput( outStream, inStream );
		{
			std::string actual = outStream.str();  // alphabetical (case insensitive) order
			std::string expected = "FAILED; 2 ran; 1 failed; 3 seconds\n\n";

			assert( expected == actual );
		}
		{
			std::stringstream  inStream2( ConsoleSpecRunner::kSummaryAbbrev + "\n" ); 
			std::stringstream  outStream2;

			runner.processInput( outStream2, inStream2 );

			std::string actual2 = outStream2.str();  // alphabetical (case insensitive) order
			std::string expected2 =	"FAILED; 2 ran; 1 failed; 3 seconds\n\n";

			assert( expected2 == actual2 );
		}
	}
	deleteListContexts( contexts );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_quit_exit_command()
{
	// the context for the 'quit' command is that it exits the parsing loop.
	// here, we will just check that the 'quitting' flag gets set.
	{
		std::stringstream  inStream(ConsoleSpecRunner::kQuitCmd);
		std::stringstream  outStream;
		
		ConsoleSpecRunner runner;
		
		assert( runner.isQuitting() == false );
		runner.processInput( outStream, inStream );
		assert( runner.isQuitting() == true );
	}
	{
		std::stringstream  inStream2(ConsoleSpecRunner::kQuitAbbrev);
		std::stringstream  outStream2;
		
		ConsoleSpecRunner runner2;
		
		assert( runner2.isQuitting() == false );
		runner2.processInput( outStream2, inStream2 );
		assert( runner2.isQuitting() == true );
	}
	{
		std::stringstream  inStream3(ConsoleSpecRunner::kExitCmd);
		std::stringstream  outStream3;
		
		ConsoleSpecRunner runner3;
		
		assert( runner3.isQuitting() == false );
		runner3.processInput( outStream3, inStream3 );
		assert( runner3.isQuitting() == true );
	}
	{
		std::stringstream  inStream4(ConsoleSpecRunner::kExitAbbrev);
		std::stringstream  outStream4;
		
		ConsoleSpecRunner runner4;
		
		assert( runner4.isQuitting() == false );
		runner4.processInput( outStream4, inStream4 );
		assert( runner4.isQuitting() == true );
	}
	{
		std::stringstream  inStream5; // end-of-input also does 'quit'
		std::stringstream  outStream5;
		
		ConsoleSpecRunner runner5;
		
		assert( runner5.isQuitting() == false );
		runner5.processInput( outStream5, inStream5 );
		runner5.processInput( outStream5, inStream5 );
		assert( runner5.isQuitting() == true );
		
		assert( outStream5.str() == "" );
	}
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_selectName()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kSelectCmd 
					+ " gold" + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );		
		runner.processInput( outStream, inStream );
		ContextList selected = runner.selectedContexts();
		
		assert( selected.size() == 1 );
		assert( selected.at(0)->name() == "Gold" );
	}
	deleteListContexts( contexts );	
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_selectNameDashName()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kSelectCmd 
					+ " copper - gold" + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );		
		runner.processInput( outStream, inStream );
		ContextList selected = runner.selectedContexts();
		
		assert( selected.size() == 2 );
		assert( selected.at(0)->name() == "copper" );
		assert( selected.at(1)->name() == "Gold" );
	}
	deleteListContexts( contexts );	
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_selectNameCommaName()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kSelectCmd 
					+ " copper, silver" + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );		
		runner.processInput( outStream, inStream );
		ContextList selected = runner.selectedContexts();
		
		assert( selected.size() == 2 );
		assert( selected.at(0)->name() == "copper" );
		assert( selected.at(1)->name() == "Silver" );
	}
	{
		std::stringstream  inStream( ConsoleSpecRunner::kSelectCmd 
					+ " copper, silver, iron" + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );		
		runner.processInput( outStream, inStream );
		ContextList selected = runner.selectedContexts();
		
		assert( selected.size() == 3 );
		assert( selected.at(0)->name() == "copper" );
		assert( selected.at(1)->name() == "Silver" );
		assert( selected.at(2)->name() == "iron" );
	}
	deleteListContexts( contexts );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_clear_command()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kSelectCmd 
					+ " copper, silver" + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );		
		runner.processInput( outStream, inStream );
		ContextList selected = runner.selectedContexts();
		
		assert( selected.size() == 2 );
		assert( selected.at(0)->name() == "copper" );
		assert( selected.at(1)->name() == "Silver" );
		
		std::stringstream  inStream2( ConsoleSpecRunner::kClearCmd + "\n" ); 
		runner.processInput( outStream, inStream2 );
		selected = runner.selectedContexts();
		
		assert( selected.size() == 0 );
	}
	deleteListContexts( contexts );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_cl_command()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kSelectCmd 
					+ " copper, iron" + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );		
		runner.processInput( outStream, inStream );
		ContextList selected = runner.selectedContexts();
		
		assert( selected.size() == 2 );
		assert( selected.at(0)->name() == "copper" );
		assert( selected.at(1)->name() == "iron" );
		
		std::stringstream  inStream2( ConsoleSpecRunner::kClearAbbrev + "\n" ); 
		runner.processInput( outStream, inStream2 );
		selected = runner.selectedContexts();
		
		assert( selected.size() == 0 );
	}
	deleteListContexts( contexts );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_list_quick_command()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kListCmd + " " + 
			kQuickOnlyCmd + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );

		runner.processInput( outStream, inStream );
		{
			std::string actual = outStream.str();  // alphabetical (case insensitive) order
			std::string expected =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"Silver  FAIL    yes         1         \n"
							"Gold    pass    yes         2         \n\n\n";

			assert( expected == actual );
		}
		{
			std::stringstream  inStream2( ConsoleSpecRunner::kListQuickAbbrev + "\n" ); 
			std::stringstream  outStream2;

			runner.processInput( outStream2, inStream2 );

			std::string actual2 = outStream2.str();  // alphabetical (case insensitive) order
			std::string expected2 =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"Silver  FAIL    yes         1         \n"
							"Gold    pass    yes         2         \n\n\n";

			assert( expected2 == actual2 );
		}
	}
	deleteListContexts( contexts );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_list_new_command()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kListCmd + " " + 
			kNewFirstCmd + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );

		runner.processInput( outStream, inStream );
		{
			std::string actual = outStream.str();  // alphabetical (case insensitive) order
			std::string expected =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"copper  pass    no          3         \n"
							"iron    FAIL    no          4         \n\n\n";

			assert( expected == actual );
		}
		{
			std::stringstream  inStream2( ConsoleSpecRunner::kListNewAbbrev + "\n" ); 
			std::stringstream  outStream2;

			runner.processInput( outStream2, inStream2 );

			std::string actual2 = outStream2.str();  // alphabetical (case insensitive) order
			std::string expected2 =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"copper  pass    no          3         \n"
							"iron    FAIL    no          4         \n\n\n";

			assert( expected2 == actual2 );
		}
	}
	deleteListContexts( contexts );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void consoleSpecRunner_processes_list_selected_command()
{
	ContextList contexts;
	{
		std::stringstream  inStream( ConsoleSpecRunner::kListCmd + " "
					+ kSelectedCmd + "\n" ); 
		std::stringstream  outStream;

		ConsoleSpecRunner runner;
		addSilverEtcToRunner( runner, contexts );				
		runner.selectOneName( "copper" );
		runner.selectOneName( "Silver" );
		
		ContextList selContexts = runner.selectedContexts();
		assert( selContexts.size() == 2 );
		assert( selContexts.at(0)->name() == "copper" );
		assert( selContexts.at(1)->name() == "Silver" );

		runner.processInput( outStream, inStream );
		{
			std::string actual = outStream.str();  // alphabetical (case insensitive) order
			std::string expected =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"copper  pass    no          3         \n"
							"Silver  FAIL    yes         1         \n\n\n";

			assert( expected == actual );
		}
		{
			std::stringstream  inStream2( ConsoleSpecRunner::kListSelectedAbbrev + "\n" ); 
			std::stringstream  outStream2;

			runner.processInput( outStream2, inStream2 );

			std::string actual2 = outStream.str();  // alphabetical (case insensitive) order
			std::string expected2 =	
							"Name    Result  HasBeenRun  Duration  \n"
							"----    ------  ----------  --------  \n"
							"copper  pass    no          3         \n"
							"Silver  FAIL    yes         1         \n\n\n";

			assert( expected2 == actual2 );
		}
	}
	deleteListContexts( contexts );
}

//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

